package com.p7.architect.store.shoppingcart.domain.model.shoppingcart;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import com.p7.architect.store.shoppingcart.domain.model.value.SkuId;
import com.p7.architect.store.shoppingcart.domain.model.value.StoreId;
import com.p7.architect.store.shoppingcart.domain.model.value.UserId;
import com.p7.architect.store.shoppingcart.domain.shared.Aggregate;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
public class ShoppingCart implements Aggregate<ShoppingCartId> {

    private ShoppingCartId shoppingCartId;

    private UserId userId;

    private StoreId storeId;

    private Map<SkuId, ShoppingItem> items = new LinkedHashMap<>();

    @Builder
    public ShoppingCart(ShoppingCartId shoppingCartId, UserId userId, StoreId storeId, List<ShoppingItem> items) {
        this.shoppingCartId = shoppingCartId;
        this.setUserId(userId);
        this.setStoreId(storeId);
        this.setItems(items);
    }

    public ShoppingCartId getShoppingCartId() {
        return shoppingCartId;
    }

    public List<ShoppingItem> getItems() {
        return new ArrayList<>(items.values());
    }

    private void setItems(List<ShoppingItem> itemList) {
        items = CollUtil.emptyIfNull(itemList).stream().collect(
                Collectors.toMap(ShoppingItem::getSkuId, Function.identity()));
    }

    public ShoppingCart(UserId userId, StoreId storeId) {
        this.setUserId(userId);
        this.setStoreId(storeId);
    }

    public UserId getUserId() {
        return userId;
    }

    private void setUserId(UserId userId) {
        Validator.validateNotNull(userId, "userId is required");
        this.userId = userId;
    }

    public StoreId getStoreId() {
        return storeId;
    }

    private void setStoreId(StoreId storeId) {
        Validator.validateNotNull(storeId, "storeId is required");
        this.storeId = storeId;
    }

    public void addItem(SkuId skuId, ItemNum itemNum) {
        final ShoppingItem cartItem = items.computeIfAbsent(skuId, k -> new ShoppingItem(k, new ItemNum(0)));
        cartItem.addNum(itemNum);
    }

    @Override
    public ShoppingCartId getId() {
        return this.shoppingCartId;
    }

    public boolean updateItems(SkuId skuId, ItemNum itemNum) {
        ShoppingItem originItem = items.get(skuId);
        if (null == originItem) {
            log.info("ShoppingCart#updateItems originItem is null, skuId: {}", skuId);
            return false;
        }
        originItem.updateNum(itemNum);
        return true;
    }

    public void removeItems(List<SkuId> skuIds) {
        skuIds.forEach(skuId -> items.remove(skuId));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ShoppingCart shoppingCart = (ShoppingCart) o;

        return shoppingCartId.sameValueAs(shoppingCart.shoppingCartId);
    }

    @Override
    public int hashCode() {
        return shoppingCartId.hashCode();
    }
}
